package com.pi.shisan.service.util;

import com.pi.shisan.AsCloseable;
import com.pi.shisan.component.impl.LocalDateComponent;
import com.pi.shisan.component.impl.LocalTimeComponent;
import com.pi.shisan.component.impl.MusicEffectComponent;
import com.pi.shisan.component.impl.ProcessStateComponent;
import com.pi.shisan.component.impl.ScrollTextComponent;
import com.pi.shisan.component.impl.TimeFormatComponent;
import com.pi.shisan.component.impl.WeatherComponent;
import com.pi.shisan.component.util.ComponentThread;
import com.pi.shisan.service.exception.BusinessException;
import com.pi.shisan.util.spipoint.MergedSpi;
import com.pi.shisan.util.spipoint.MultipleFlushSpi;

import java.util.function.Supplier;

public class ComponentManager {

    private MultipleFlushSpi mergedSpi;

    private AsCloseable lastOpened;

    private boolean hasExit;

    private int level = 1;

    public ComponentManager (int w, int h, boolean useRotate) {
        mergedSpi = new MultipleFlushSpi(new MergedSpi(w,h,useRotate));
        mergedSpi.init();
    }

    public ComponentManager (MultipleFlushSpi spi) {
        this.mergedSpi = spi;
    }

    public int getLightLevel() {
        return level;
    }

    public void setupLightLevel(int level) {
        int _level = level & 0xF;
        ComponentThread.execute(()->{
            mergedSpi.lightLevel(_level);
        });
        this.level = _level;
    }


    private void checkAndClose() {
        AsCloseable lastOpened = this.lastOpened;
        if (lastOpened != null) {
            lastOpened.close();
            ComponentThread.execute(()->{
                mergedSpi.clear();
            });
        }
        if (hasExit) {
            throw new BusinessException("屏显已关闭，无法再接收任务");
        }
    }

    /**
     * 整点报时展示
     */
    public synchronized AClockComponents showAClockNotify() {
        final AsCloseable last = this.lastOpened;
        if (last != null && last.getClass() == AClockComponents.class) {
            return (AClockComponents) last;
        }
        checkAndClose();
        LocalTimeComponent localTimeComponent = new LocalTimeComponent(mergedSpi,mergedSpi,true);
        localTimeComponent.setX(2);
        localTimeComponent.setY(10);
        localTimeComponent.setW(32);
        localTimeComponent.start();
        AClockComponents lastOpened =  new AClockComponents(localTimeComponent);
        this.lastOpened = lastOpened;
        return lastOpened;
    }

    /**
     * 平时无任何事件的时钟展示
     */
    public synchronized ClockComponents showClock(Supplier<WeatherComponent.WeatherInfo> weatherSupplier) {
        final AsCloseable last = this.lastOpened;
        if (last != null && last.getClass() == ClockComponents.class) {
            return (ClockComponents) last;
        }
        checkAndClose();
        LocalDateComponent localDateComponent = new LocalDateComponent(mergedSpi, mergedSpi);
        LocalTimeComponent localTimeComponent = new LocalTimeComponent(mergedSpi, mergedSpi,true);
        WeatherComponent weatherComponent = new WeatherComponent(mergedSpi,mergedSpi);
        localDateComponent.setX(0);
        localDateComponent.setY(2);
        localDateComponent.setH(5);
        localTimeComponent.setX(1);
        localTimeComponent.setY(17);

        weatherComponent.setW(32);
        weatherComponent.setH(8);
        weatherComponent.setX(0);
        weatherComponent.setY(10);
        weatherComponent.setWeatherInfoSupplier(weatherSupplier);

        localDateComponent.start();
        localTimeComponent.start();
        weatherComponent.start();
        ClockComponents lastOpened = new ClockComponents(localDateComponent,localTimeComponent,weatherComponent);
        this.lastOpened = lastOpened;
        return lastOpened;
    }

    /**
     * 平时无任何事件的时钟展示
     * 精简模式，如晚上睡觉，LED亮的太多，会导致难以入眠，所以设置一个精简模式
     * @return
     */
    public synchronized SimpleClockComponents showClockSimple() {
        final AsCloseable last = this.lastOpened;
        if (last != null && last.getClass() == SimpleClockComponents.class) {
            return (SimpleClockComponents) last;
        }
        checkAndClose();
        LocalTimeComponent localTimeComponent = new LocalTimeComponent(mergedSpi, mergedSpi,false);
        localTimeComponent.setX(7);
        localTimeComponent.setY(9);

        localTimeComponent.start();
        SimpleClockComponents lastOpened = new SimpleClockComponents(localTimeComponent);
        this.lastOpened = lastOpened;
        return lastOpened;
    }

    /**
     * 闹铃展示
     */
    public synchronized AlarmComponents showAlarm() {
        final AsCloseable last = this.lastOpened;
        if (last != null && last.getClass() == AlarmComponents.class) {
            return (AlarmComponents) last;
        }
        checkAndClose();
        MusicEffectComponent leftMusicEffectComponent = new MusicEffectComponent(mergedSpi, mergedSpi);
        MusicEffectComponent rightMusicEffectComponent = new MusicEffectComponent(mergedSpi, mergedSpi);
        ScrollTextComponent scrollTextComponent = new ScrollTextComponent(mergedSpi, mergedSpi);
        LocalTimeComponent localTimeComponent = new LocalTimeComponent(mergedSpi, mergedSpi);
        leftMusicEffectComponent.setW(2);
        leftMusicEffectComponent.setY(16);
        leftMusicEffectComponent.setH(8);

        rightMusicEffectComponent.setX(30);
        rightMusicEffectComponent.setW(2);
        rightMusicEffectComponent.setY(16);
        rightMusicEffectComponent.setH(8);

        scrollTextComponent.setW(32);

        localTimeComponent.setX(7);
        localTimeComponent.setY(17);
        localTimeComponent.setW(17);

        leftMusicEffectComponent.start();
        rightMusicEffectComponent.start();
        scrollTextComponent.start();
        localTimeComponent.start();

        AlarmComponents lastOpened = new AlarmComponents(leftMusicEffectComponent, rightMusicEffectComponent, scrollTextComponent, localTimeComponent);
        this.lastOpened = lastOpened;
        return lastOpened;
    }

    /**
     * 音乐播放展示
     */
    public synchronized MusicEffectComponents showMusicEffect() {
        final AsCloseable last = this.lastOpened;
        if (last != null && last.getClass() == MusicEffectComponents.class) {
            return (MusicEffectComponents) last;
        }
        checkAndClose();
        TimeFormatComponent timeFormatComponent = new TimeFormatComponent(mergedSpi,mergedSpi);
        timeFormatComponent.setX(3);
        timeFormatComponent.setY(16);
        timeFormatComponent.start();

        ScrollTextComponent scrollTextComponent = new ScrollTextComponent(mergedSpi,mergedSpi);
        scrollTextComponent.setX(3);
        scrollTextComponent.setW(26);
        scrollTextComponent.start();

        ProcessStateComponent processStateComponent = new ProcessStateComponent(mergedSpi,mergedSpi);
        processStateComponent.setX(3);
        processStateComponent.setW(26);
        processStateComponent.setY(22);
        processStateComponent.start();

        MusicEffectComponent leftMusicEffectComponent = new MusicEffectComponent(mergedSpi,mergedSpi);
        leftMusicEffectComponent.setW(2);
        leftMusicEffectComponent.setH(24);
        leftMusicEffectComponent.start();
        MusicEffectComponent rightMusicEffectComponent = new MusicEffectComponent(mergedSpi,mergedSpi);
        rightMusicEffectComponent.setH(24);
        rightMusicEffectComponent.setW(2);
        rightMusicEffectComponent.setX(30);
        rightMusicEffectComponent.start();

        MusicEffectComponents lastOpened = new MusicEffectComponents(leftMusicEffectComponent, rightMusicEffectComponent, scrollTextComponent, timeFormatComponent, processStateComponent);
        this.lastOpened = lastOpened;
        return lastOpened;
    }

    public synchronized void exit() {
        hasExit = true;
        try {
            checkAndClose();
        } catch (Exception e) {
        }
        try {
            mergedSpi.close();
        } catch (Exception e) {
        }
    }

    public static class ClockComponents implements AsCloseable {
        private LocalDateComponent localDateComponent;
        private LocalTimeComponent localTimeComponent;
        private WeatherComponent weatherComponent;

        public ClockComponents(LocalDateComponent localDateComponent, LocalTimeComponent localTimeComponent,WeatherComponent weatherComponent) {
            this.localDateComponent = localDateComponent;
            this.localTimeComponent = localTimeComponent;
            this.weatherComponent = weatherComponent;
        }

        public LocalDateComponent getLocalDateComponent() {
            return localDateComponent;
        }

        public LocalTimeComponent getLocalTimeComponent() {
            return localTimeComponent;
        }

        @Override
        public void close() {
            if (localDateComponent != null) {
                localDateComponent.close();
            }
            if (localTimeComponent != null) {
                localTimeComponent.close();
            }
            if (weatherComponent != null) {
                weatherComponent.close();
            }
        }
    }

    public static class SimpleClockComponents implements AsCloseable {
        private LocalTimeComponent localTimeComponent;

        public SimpleClockComponents(LocalTimeComponent localTimeComponent) {
            this.localTimeComponent = localTimeComponent;
        }

        public LocalTimeComponent getLocalTimeComponent() {
            return localTimeComponent;
        }

        @Override
        public void close() {
            if (localTimeComponent != null) {
                localTimeComponent.close();
            }
        }
    }

    public static class AClockComponents  implements AsCloseable {
        private LocalTimeComponent component;

        public AClockComponents(LocalTimeComponent component) {
            this.component = component;
        }

        public LocalTimeComponent getComponent() {
            return component;
        }

        @Override
        public void close() {
            component.close();
        }
    }

    public static class MusicEffectBaseComponent implements AsCloseable {
        protected MusicEffectComponent leftMusicEffectComponent;
        protected MusicEffectComponent rightMusicEffectComponent;
        protected ScrollTextComponent scrollTextComponent;

        protected TimeFormatComponent timeFormatComponent;
        protected ProcessStateComponent processStateComponent;

        public MusicEffectBaseComponent(MusicEffectComponent leftMusicEffectComponent, MusicEffectComponent rightMusicEffectComponent, ScrollTextComponent scrollTextComponent) {
            this.leftMusicEffectComponent = leftMusicEffectComponent;
            this.rightMusicEffectComponent = rightMusicEffectComponent;
            this.scrollTextComponent = scrollTextComponent;
        }

        public MusicEffectComponent getLeftMusicEffectComponent() {
            return leftMusicEffectComponent;
        }

        public MusicEffectComponent getRightMusicEffectComponent() {
            return rightMusicEffectComponent;
        }

        public ScrollTextComponent getScrollTextComponent() {
            return scrollTextComponent;
        }

        public TimeFormatComponent getTimeFormatComponent() {
            return timeFormatComponent;
        }

        public ProcessStateComponent getProcessStateComponent() {
            return processStateComponent;
        }

        @Override
        public void close() {
            scrollTextComponent.close();
        }
    }

    public static class AlarmComponents extends MusicEffectBaseComponent{
        protected LocalTimeComponent localTimeComponent;
        public AlarmComponents(MusicEffectComponent leftMusicEffectComponent, MusicEffectComponent rightMusicEffectComponent, ScrollTextComponent scrollTextComponent, LocalTimeComponent localTimeComponent) {
            super(leftMusicEffectComponent, rightMusicEffectComponent, scrollTextComponent);
            this.localTimeComponent = localTimeComponent;
        }

        public LocalTimeComponent getLocalTimeComponent() {
            return localTimeComponent;
        }

        @Override
        public void close() {
            super.close();
            this.localTimeComponent.close();
        }
    }

    public static class MusicEffectComponents extends MusicEffectBaseComponent{

        public MusicEffectComponents(MusicEffectComponent leftMusicEffectComponent, MusicEffectComponent rightMusicEffectComponent, ScrollTextComponent scrollTextComponent) {
            super(leftMusicEffectComponent, rightMusicEffectComponent, scrollTextComponent);
        }

        public MusicEffectComponents(MusicEffectComponent leftMusicEffectComponent, MusicEffectComponent rightMusicEffectComponent, ScrollTextComponent scrollTextComponent,TimeFormatComponent timeFormatComponent,ProcessStateComponent processStateComponent) {
            super(leftMusicEffectComponent, rightMusicEffectComponent, scrollTextComponent);
            this.timeFormatComponent = timeFormatComponent;
            this.processStateComponent = processStateComponent;
        }

        @Override
        public void close() {
            super.close();
            processStateComponent.close();
        }
    }
}
